<template>
<!--  vue2中组件只能有一个根节点:<div>,当多个元素(标签)并列显示的时候,必须要使用根节点<div>将它们包裹起来,不然报错 -->
<div>
<!--  下面中的:data相当于绑定了一个属性,这个属性为menus,这个属性跟组件里面的menus进行绑定-->
  <el-tree :data="menus" :props="defaultProps"
           :expand-on-click-node="false"
           show-checkbox
           node-key="catId"
           :default-expanded-keys="expandedKey"> <!-- :expand-on-click-node="false"这个表示只有点击前面箭头的时候才会展开/合并
                                                        show-checkbox表示节点是否可被选择(也就是在前面加可以勾选的复选框)
                                                        node-key="catId" -> el-tree标签里一定要设置node-key这个属性,
                                                       它是每个树节点用来作为唯一标识的属性,整棵树应该是唯一的
                                                       这样我们el-tree就能分辨每一个节点的不同 -->

<!--   我们使用Element UI中的scoped solt方式进行删除,只需要给<el-tree>这个标签体里面复制过来一个<span>标签 -->
    <span class="custom-tree-node" slot-scope="{ node, data }">
        <span>{{ node.label }}</span>
        <span>
<!--      node就是当前节点对象,只有当前节点的层级是1级或2级时(node.level<=2),我们才来给他展示Append这个按钮,这时才可以添加子分类 -->
          <el-button
            v-if="node.level<=2"
            type="text"
            size="mini"
            @click="() => append(data)">
            Append
          </el-button>
          <!-- 修改按钮-->
          <el-button
            type="text"
            size="mini"
            @click="edit(data)">
            Edit
          </el-button>
<!--      只有当前节点没有子节点我们才可以显示Delete按钮 -->
          <el-button
            v-if="node.childNodes.length==0"
            type="text"
            size="mini"
            @click="() => remove(node, data)">
            Delete
          </el-button>
        </span>
      </span>
  </el-tree>

  <el-dialog
    :title="title"
    :visible.sync="dialogVisible"
    :close-on-click-modal="false"
    width="30%"> <!-- visible.sync 这个加了.sync的修饰符是用来实现父子组件中的数据双向绑定的功能的 -->
<!-- :model是v-bind:model的简写,:model中的model就是表单数据对象(Element UI中有解释),-->
    <el-form :model="category"> <!-- el-form 组件的 model用于绑定表单数据对象，通过:model属性将表单元素（如el-input、el-select等）的数据绑定到指定对象。
                                     此时:model是el-form的属性，用于定义表单数据模型，与后端接口参数匹配。-->
      <el-form-item label="分类名称">
        <el-input v-model="category.name" autocomplete="off"></el-input>
        <!-- el-input等表单元素的v-model用于双向数据绑定,此时v-model直接绑定到表单项的数据属性（如用户名），实现用户输入自动更新数据对象属性。-->
        <!-- 核心区别: 1.作用范围不同‌：:model用于表单整体数据绑定（如用户对象），v-model用于表单项的双向绑定（如用户名、密码等具体字段）。
                      2.实现机制不同‌：:model通过单向绑定传递数据，v-model实现双向绑定（用户输入自动同步到模型对象）。
                      单向绑定(v-bind):
                              数据流向‌：仅支持从模型到视图的单向流动，视图无法更新模型数据。
                              ‌适用场景‌：适用于进度条、图表等非表单类组件，数据仅需从组件获取，无需用户修改。
                      双向绑定(v-model):
                              数据流向‌：支持模型与视图双向同步更新，用户修改视图时会自动更新模型数据。
                              适用场景‌：适用于输入框、选择器等表单类组件，需实时同步用户输入与后台数据。
                      总结: 单向绑定仅用于数据展示，双向绑定用于需要用户交互更新的场景。 -->
      </el-form-item>
      <el-form-item label="图标">
        <el-input v-model="category.icon" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="计量单位">
        <el-input v-model="category.productUnit" autocomplete="off"></el-input>
      </el-form-item>
    </el-form>
    <span slot="footer" class="dialog-footer">
    <el-button @click="dialogVisible = false">取 消</el-button>
    <el-button type="primary" @click="submitData">确 定</el-button>
  </span>
  </el-dialog>
</div>
</template>

<script>
export default {
  name: "category",
  data(){
    return{
      menus:[],
      expandedKey:[],
      title:"",
      dialogType:"",// edit(修改),add(添加)
      dialogVisible:false,
      category:{
        name:"",
        parentCid:0,
        catLevel:0,
        showStatus:1,
        sort:0,
        catId:null,
        icon:"",
        productUnit:"",
      },
      defaultProps:{
        //下面这个children指的就是我们返回的数据中每一个对象里面的哪个字段表示的是他的子节点,我们的就是children这个字段是子节点
        children: 'children',
        //下面这个label指的就是我们的哪个字段要进行显示,我们的每一个菜单都有一个name属性,它是要真正进行显示的
        label: 'name'
      }
    };
  },
  methods: {
    submitData(){
      if (this.dialogType=="add"){
        this.addCategory();
      }
      if (this.dialogType=="edit"){
        this.editCategory();
      }
    },
    //添加三级分类的方法
    addCategory(){
      console.log("要提交给服务器的三级分类数据",this.category);
      this.$http({
        url: this.$http.adornUrl('/product/category/save'),
        method: 'post',
        data: this.$http.adornData(this.category, false)
      }).then(({data}) => {
        this.$message({
          message: '菜单保存成功',
          type: 'success'
        });
        //关闭对话框
        this.dialogVisible=false;
        //刷新出新的菜单
        this.getMenus();
        //设置需要默认展开的菜单
        this.expandedKey=[this.category.parentCid];
      })
    },
    //修改三级分类数据
    editCategory(){
      //我们希望修改的时候也只发送分类的id,分类的名字,分类的图标地址以及分类的计量单位,
      //从category中解构出我想要的内容
      var {catId,name,icon,productUnit} = this.category;
      this.$http({
        url: this.$http.adornUrl('/product/category/update'),
        method: 'post',
        //我们真正要发的数据我们得提取一下,我们不能将this.category整个发出去,因为this.category整个发出去的话,
        //他还包含了显示的状态(showStatus),排序(sort),以及层级(catLevel)等等,这些属性我们没给他回显,如果发出去的话
        //数据库就会用this.category中这些属性设置的默认值把他以前的值(层级...)替换掉,如果我们不发,相当于这些属性的值为空(null)的话,
        //那我们这次更新,我们的Controller里面的这个更新其实是一个动态更新,为空(null)的字段他就不会更新,所以我们不想更新的数据,不往处发就行了
        //或者我们直接发this.category也是可以的,但是就必须把this.category中的所有字段全部在下面的edit(data)方法中回显出来,如果不回显这些字段的话
        //就会导致数据表里面这些不回显的字段被默认值给他更新掉,而且这样也增加了数据库的读写,所以还是推荐不发出去的写法
        data: this.$http.adornData({catId,name,icon,productUnit}, false)
      }).then(({data}) => {
        this.$message({
          message: '菜单修改成功',
          type: 'success'
        });
        //关闭对话框
        this.dialogVisible=false;
        //刷新出新的菜单
        this.getMenus();
        //设置需要默认展开的菜单
        this.expandedKey=[this.category.parentCid];
      })
    },
    edit(data){
      console.log("要修改的数据",data);
      this.title="修改分类";
      this.dialogType="edit";
      this.dialogVisible=true;
      //发送请求获取当前节点最新的数据
      this.$http({
        //分类id(catId)是动态获取的,我们刚才点了那个修改,就应该是获取它的分类id
        url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
        method: 'get',
      }).then(({data}) =>{
        //请求成功,这个data是服务器返回的data
        console.log("要回显的数据",data);
        this.category.name=data.data.name;
        this.category.catId=data.data.catId;
        this.category.icon=data.data.icon;
        this.category.productUint=data.data.productUnit;
        this.category.parentCid=data.data.parentCid;
      })
    },
    getMenus(){
      this.$http({
        url: this.$http.adornUrl('/product/category/list/tree'),
        method: 'get',
      }).then(({data}) => { //把data解构出来(也就是加上{},原来是data),因为data里面才是我们数组中的数据
        console.log("成功获取到的菜单数据:",data.data)
        //查到了数据就把这个数据赋值给菜单这个属性
        this.menus=data.data;
      })
    },
    append(data){
      console.log("append",data);
      this.dialogType="add";
      this.title="添加分类";
      //this.category={};//注意:不能这么写,以前的写法错了, ={}是全空,并没有填写默认值,数据没有值,数据肯定出错
      this.dialogVisible=true;
      this.category.showStatus=1;
      //可以在控制台看出来,我点了Append的菜单id(catId)就是我要添加的新菜单的父id
      this.category.parentCid=data.catId;
      //这个层级我们害怕是字符串,所以我们给它乘1转化成一个数字,然后再加1
      this.category.catLevel=data.catLevel * 1 + 1 ;
      //点击添加的时候,这些修改后的回显数据要给他清空掉
      this.category.catId=null;
      this.category.name="";
      this.category.icon="";
      this.category.productUint="";
      this.category.sort=0;
      this.category.showStatus=1;
    },
    remove(node,data){
      var ids = [data.catId];
      this.$confirm(`是否删除[${data.name}]`,'提示',{
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.$http({
          url: this.$http.adornUrl('/product/category/delete'),
          method: 'post',
          data: this.$http.adornData(ids,false)
        }).then(({data}) => {
          this.$message({
            message: '菜单删除成功',
            type: 'success'
          });
          //刷新出新的菜单
          this.getMenus();
          //设置需要默认展开的菜单
          this.expandedKey=[node.parent.data.catId];
          this.dataListLoading = false
        })
      });
      console.log("remove",node,data)
    }
  },
  created() {
    this.getMenus();
  }
}
</script>

<style scoped>

</style>
